#include "Player.h"
#include "Game.h"
#include "PlatformObst.h"
#include <math.h>
#include "DestroyEntityMsg.h"
#include "MessageSystem.h"
#include "Abilities\Spin.h"
#include "Abilities\Shield.h"
#include "EventSystem.h"
#include "Enemies\Enemy.h"
#include "Gameplay_States\GameplayState.h"
#include <Windows.h>

CPlayer::CPlayer(void)
{
	this->m_bPlayerOnPlatform = false;
	this->m_bOnEnemy = false;
	CEventSystem::GetInstance()->RegisterClient("jump", this);
	CEventSystem::GetInstance()->RegisterClient("NEXT",this);
	CEventSystem::GetInstance()->RegisterClient("TakePlayerDamage",this);
	CEventSystem::GetInstance()->RegisterClient("PlayerAttack",this);
	CEventSystem::GetInstance()->RegisterClient("ShieldMode",this);
	this->m_bFaceing=true;
	this->m_bShield=false;
}


CPlayer::~CPlayer(void)
{
	CEventSystem::GetInstance()->UnregisterClientAll(this);
}



void CPlayer::SetPotLifeLoss(int nPotLifeloss)
{
	if(nPotLifeloss > this->m_nHealth)
		m_nPotLifeLoss = m_nHealth;
	else
		m_nPotLifeLoss = nPotLifeloss;
}

void CPlayer::Update(float fElapsedTime)
{

	if(m_fTimeLeftForCurrentAbility > 0)
		m_fTimeLeftForCurrentAbility -= fElapsedTime;

	if(UseAbility() == false)
		this->m_nPotLifeLoss = 0;

	if(this->m_nBAttackEffectCount > 0)
		m_fAttackCooldown -= fElapsedTime;

	if(this->m_nSpinAttackEffectCount > 0)
		m_fSpinCooldown -= fElapsedTime;

	if(m_fAttackCooldown <= 0)
	{
		m_nBAttackEffectCount = 0;
		m_fAttackCooldown = .6f;
	}
	if(m_fSpinCooldown <= 0)
	{
		m_nSpinAttackEffectCount = 0;
		m_fSpinCooldown = 1.0f;
	}
	AbilityFinished();

	CEntity::Update(fElapsedTime);

	//ANIMATION NOTES: Set H/W with the pAM's GetCHeight an GetCWidth passing in the objects aniinfo
	m_pAM= CAnimationManager::GetInstance();
	m_pAM->Update(fElapsedTime,this->m_cAniInfo);
	//Get current animations
	this->SetHeight(m_pAM->GetCHeight(m_cAniInfo));
	this->SetWidth(m_pAM->GetCWidth(m_cAniInfo));

	if(this->GetPosY() + this->GetHeight() < CGame::GetInstance()->GetHeight() && this->OnPlatform() == false)
	{
		//check if animation is jumping. set to it
		this->SetVelY(this->GetVelY()+5);
	}
	if(this->GetPosY() + this->GetHeight() > (int)CGame::GetInstance()->GetHeight())
	{
		this->SetPosY((float)CGame::GetInstance()->GetHeight()-this->GetHeight());
	}
	CGameplayState::Camera cam = CGameplayState::GetInstance()->GetCamera();
	if(this->GetPosX() <= cam.camPosX)
		if(this->GetVelX() < 0)
		{
			this->SetVelX(0);
			this->SetPosX((float)cam.camPosX);
		}
/*	if(this->GetPosX() > cam.camPosX - CGame::GetInstance()->GetWidth()/2)
		cam.camPosX = this->GetPosX() - CGame::GetInstance()->GetWidth()/2;*/
	/*if(this->GetPosX() + this->GetWidth() >= CGame::GetInstance()->GetWidth())
		if(this->GetVelX() > 0)
		{
			this->SetVelX(0);
			this->SetPosX((float)CGame::GetInstance()->GetWidth()-this->GetWidth());
		}*/
}

void CPlayer::Render(void)
{
	//swap to draw with anmation
	m_pAM= CAnimationManager::GetInstance();
	m_pD= CSGD_Direct3D::GetInstance();

	//	 collisionRect
	m_pD->DrawRect((m_pAM->GetCRECT(this->m_cAniInfo,(int)GetPosX() - CGameplayState::GetInstance()->GetCamera().camPosX,(int)GetPosY())),0,0,255);

	m_pAM->Render(m_cAniInfo,(int)GetPosX() - CGameplayState::GetInstance()->GetCamera().camPosX, (int)GetPosY(),1.0,this->GetFacing());

}

void CPlayer::Init(void)
{
	CGame* pGame = CGame::GetInstance();
	m_pTM = CSGD_TextureManager::GetInstance();
	m_pAM=  CAnimationManager::GetInstance();
	m_pES = CEventSystem::GetInstance();
	//Set planned animations
	m_cAniInfo.SetName("PlayerWalk");
	m_cAniInfo.SetNext("PlayerAttack");

	this->SetType(OBJ_PLAYER);
	m_cAniInfo.SetTime(0);
	m_cAniInfo.SetFrame(0);
	m_fAttackCooldown = .6f;
	m_fSpinCooldown = 1.0f;
	this->m_nBAttackEffectCount = 0;
	this->m_nSpinAttackEffectCount = 0;
	this->SetDensity(1);
	//set heigh width based on farme

	this->SetHeight(m_pAM->GetCHeight(m_cAniInfo));
	this->SetWidth(m_pAM->GetCWidth(m_cAniInfo));
	m_bSpin = false;
	this->SetPosX((float)CGame::GetInstance()->GetWidth()/2);
	this->m_bFaceing=false;
	this->SetPosY((float)pGame->GetHeight()- this->GetHeight() - 500);	//gravity	this->m_eType = OBJ_PLAYER;
	this->SetVelX(0);
	this->SetVelY(0);
	this->m_bPlayerOnPlatform = false;
	this->m_bOnEnemy = false;
	this->m_nCurrentHits = 0;
	this->m_nHealth = 100;
	this->m_nHitsNeededForCurrentAbility = 0;
	this->m_nMaxHealth = 100;
	this->m_nPotLifeLoss = 0;
	 m_bShield =false;
	m_nShieldCount =0;
}

bool CPlayer::CheckCollision(IEntity* pOther)
{
	m_pAM=  CAnimationManager::GetInstance();
	RECT ZERORECT ={0,0,0,0};
	if(CEntity::CheckCollision(pOther) == false)
		return false;
	switch(pOther->GetType())
	{
	case OBJ_PLATFORM:
		{
			RECT collisionRect = pOther->GetRect();
			RECT Collider = m_pAM->GetCRECT(this->m_cAniInfo,(int)GetPosX() - CGameplayState::GetInstance()->GetCamera().camPosX,(int)GetPosY());
			RECT Temp = {0,0,0,0};
			if(IntersectRect(&Temp,&Collider,&collisionRect)==TRUE)
			{
				int L,T,R,B;
				L=Temp.left;T=Temp.top;R=Temp.right;B=Temp.bottom;

				if(this->GetPosY() <= collisionRect.bottom)
					this->SetVelY(this->GetVelY() + 5);
				if(this->GetPosY() >= collisionRect.top-3 )
				{
					if	(L!=0)
					{
						this->SetVelX(0);
						this->SetPosX((float)collisionRect.left-this->GetWidth());
					}

					if(R!=0)
					{
						this->SetVelX(0);
						this->SetPosX((float)collisionRect.right);
					}
				}
				if(this->GetVelY() > 0)
				{
					if(B!=0)
					{
						this->OnPlatform(true);

						if(this->GetVelY() > 0)
							this->SetVelY(0);	
					}	
				}
			}
		}
		break;

	case OBJ_ENEMY:
		{

			RECT collisionRect = pOther->GetRect();
			RECT Collider = m_pAM->GetCRECT(this->m_cAniInfo,(int)GetPosX() - CGameplayState::GetInstance()->GetCamera().camPosX,(int)GetPosY());
			RECT Temp = {0,0,0,0};
			if(IntersectRect(&Temp,&Collider,&collisionRect)==TRUE)
			{
				int L,T,R,B;
				L=Temp.left;T=Temp.top;R=Temp.right;B=Temp.bottom;

				if(this->GetPosY() <= collisionRect.bottom)
					this->SetVelY(this->GetVelY() + 5);
				//	if(this->GetPosY() >= collisionRect.top )
				//	{
				if	(L!=0)
				{
					if(this->m_cAniInfo.GetName()=="PlayerAttack")
					{

						if(this->m_nBAttackEffectCount == 0)
							CEventSystem::GetInstance()->SendEvent("take damage");
						m_nBAttackEffectCount++;
					}
					else
					{
						if(this->GetSpin())
						{
							if(this->m_nSpinAttackEffectCount == 0)
								CEventSystem::GetInstance()->SendEvent("take damage");
							m_nSpinAttackEffectCount++;
						}
					}
					break;
				}
				if(R!=0)
				{
					if(this->m_cAniInfo.GetName()=="PlayerAttack")
					{
						if(this->m_nBAttackEffectCount == 0)
							CEventSystem::GetInstance()->SendEvent("take damage");
						m_nBAttackEffectCount++;
					}
					else
					{
						if(this->GetSpin())
						{
							if(this->m_nSpinAttackEffectCount == 0)
								CEventSystem::GetInstance()->SendEvent("take damage");
							m_nSpinAttackEffectCount++;
						}
					}
						break;
				}

			}
			//}
			if(this->GetVelY() > 0)
			{
					CEntity* pEntity = dynamic_cast<CEntity*>(pOther);
					this->OnEnemy(true);
					CEnemy* pEnemy = dynamic_cast<CEnemy*>(pOther);
					pEnemy->SetHealth(0);
					this->m_nCurrentHits++;
			}	
		}
	break;

	case OBJ_TILE:
		{
			RECT collisionRect = pOther->GetRect();
			RECT Collider = m_pAM->GetCRECT(this->m_cAniInfo,(int)GetPosX(),(int)GetPosY());
			
			RECT Temp = {0,0,0,0};
			
			if(IntersectRect(&Temp,&Collider,&collisionRect)==TRUE)
			{
				int L,T,R,B;
				L=Temp.left;T=Temp.top;R=Temp.right;B=Temp.bottom;

				if(this->GetPosY() <= collisionRect.bottom)
					this->SetVelY(this->GetVelY() + 5);
				if(this->GetPosY() >= collisionRect.top-3 )
				{
					if	(R==Collider.right||L==Collider.left)
					{
						this->SetVelX(0);
						//this->SetPosX((float)collisionRect.left-this->GetWidth());
						this->SetPosX((float)Collider.left);
					}
				//	else if(L==Collider.left)
				//	{
				//		this->SetVelX(0);
				//		this->SetPosX((float)Collider.left);
				//		//this->SetPosX((float)collisionRect.right);
				//	}
				}
				if(this->GetVelY() > 0)
				{
					if(B!=0)
					{
						this->OnPlatform(true);

						if(this->GetVelY() > 0)
							this->SetVelY(0);	
					}	
				}
			}
		}
		break;
	case OBJ_EVENT:
		{
			CEventSystem::GetInstance()->SendEvent("jump", this);
		}
		break;
}
return true;
}

void CPlayer::AddAbility(CAbilities* pAbility)
{
	switch(pAbility->GetCode())
	{
	case 2:
		{
			CSpin* pSpin = dynamic_cast<CSpin*>(pAbility);
			pSpin->Init();
			this->m_pPlayerAbilities.push_back(pSpin);
		}
		break;
	case 3:
		{
			CShield* pSpin = dynamic_cast<CShield*>(pAbility);
			pSpin->Init();
			this->m_pPlayerAbilities.push_back(pSpin);
			ModShieldCount(1);
			SetShield(true);
		}
		break;
	}
}

bool CPlayer::UseAbility(void)
{
	if(this->m_pPlayerAbilities.size() > 0)
	{
		auto iter = this->m_pPlayerAbilities.begin();
		this->m_nHitsNeededForCurrentAbility = (*iter)->GetHitRequirement();
		this->m_nPotLifeLoss = (*iter)->GetHealthCost();
		if(this->m_nHealth - this->m_nPotLifeLoss < 0)
			this->m_nPotLifeLoss = this->m_nHealth;
		return true;
	}
	return false;
}

void CPlayer::AbilityFinished(void)
{
	if(this->m_nCurrentHits >= this->m_nHitsNeededForCurrentAbility && this->m_pPlayerAbilities.size() > 0)
	{
		auto iter = this->m_pPlayerAbilities.begin();

		if((*iter)->GetCode() ==3)
		{
			if(GetShieldCount()==0)
			{
				SetShield(false);
			}
			else
			{
				ModShieldCount(-1);
			}
		}

		this->m_pPlayerAbilities.pop_front();
		if(this->m_pPlayerAbilities.size() > 0)
		{
			iter = this->m_pPlayerAbilities.begin();
			this->m_fTimeLeftForCurrentAbility = (*iter)->GetAbilityTimer();
			this->m_nPotLifeLoss = (*iter)->GetHealthCost();
			if(this->m_nPotLifeLoss > this->m_nHealth)
				this->m_nPotLifeLoss = this->m_nHealth;
		}
	}
	if(this->m_fTimeLeftForCurrentAbility <= 0 && this->m_nCurrentHits < this->m_nHitsNeededForCurrentAbility && this->m_pPlayerAbilities.size() > 0)
	{
		this->m_nHealth -= this->m_nPotLifeLoss;
		this->m_nPotLifeLoss = 0;
		this->m_nHitsNeededForCurrentAbility = 0;
		auto iter = this->m_pPlayerAbilities.begin();

				if((*iter)->GetCode() ==3)
		{
			if(GetShieldCount()==0)
			{
				SetShield(false);
			}
			else
			{
				ModShieldCount(-1);
			}
		}

		this->m_pPlayerAbilities.pop_front();
		if(this->m_pPlayerAbilities.size() > 0)
		{
			iter = this->m_pPlayerAbilities.begin();
			this->m_fTimeLeftForCurrentAbility = (*iter)->GetAbilityTimer();
			this->m_nPotLifeLoss = (*iter)->GetHealthCost();
			if(this->m_nPotLifeLoss > this->m_nHealth)
				this->m_nPotLifeLoss = this->m_nHealth;
		}
	}

	//if ability finished was shield lower shield count. if count is zero, set to false.
}

void CPlayer::UpdateTimeLeft(void)
{
	if(this->m_pPlayerAbilities.size() == 1)
	{
		auto iter = this->m_pPlayerAbilities.begin();
		this->m_fTimeLeftForCurrentAbility = (*iter)->GetAbilityTimer();
		this->m_nPotLifeLoss = (*iter)->GetHealthCost();
		if(this->m_nPotLifeLoss > this->m_nHealth)
			this->m_nPotLifeLoss = this->m_nHealth;
	}
}

void CPlayer::HandleEvent(CNEvent *pEvent)
{
	if(pEvent->GetParam() == nullptr || pEvent->GetParam() == this)
	{
		if(pEvent->GetEventID() == "jump")
		{
			SetVelY(-4.0f);

			//set color or rotation
		
			if(GetShield()==true)
			{
			m_cAniInfo.SetName("PlayerShieldJump");
			m_cAniInfo.SetNext("PlayerShieldWalk");
			m_cAniInfo.SetTime(0);
			m_cAniInfo.SetFrame(0);

			}
			else 
			{
			m_cAniInfo.SetName("PlayerJump");
			m_cAniInfo.SetNext("PlayerWalk");
			m_cAniInfo.SetTime(0);
			m_cAniInfo.SetFrame(0);

			}

			
		}
		if (pEvent->GetEventID()=="NEXT")
		{


		if(GetShield()==true)
		{
		m_cAniInfo.SetName("PlayerShieldJump");
		m_cAniInfo.SetNext("PlayerShieldWalk");
		m_cAniInfo.SetTime(0);
		m_cAniInfo.SetFrame(0);
		
		}
		else
		{
			m_cAniInfo.SetName("PlayerWalk");
			m_cAniInfo.SetNext("PlayerAttack");
			m_cAniInfo.SetTime(0);
			m_cAniInfo.SetFrame(0);
		}

		}


		if(pEvent->GetEventID()=="TakePlayerDamage")
		{
			if(GetShield()==true)
			{
			m_nHealth-=2;
			}
			else
			m_nHealth-=10;
		}

		if (pEvent->GetEventID()=="PlayerAttack")
		{
		if(GetShield()==true)
		{
		m_cAniInfo.SetName("PlayerShieldJump");
		m_cAniInfo.SetNext("PlayerShieldWalk");
		m_cAniInfo.SetTime(0);
		m_cAniInfo.SetFrame(0);
		
		}
		else
		{
			m_cAniInfo.SetName("PlayerWalk");
			m_cAniInfo.SetNext("PlayerAttack");
			m_cAniInfo.SetTime(0);
			m_cAniInfo.SetFrame(0);
		}
		}

		if( pEvent->GetEventID()=="ShieldMode")
		{
			m_cAniInfo.SetName("PlayerShieldWalk");
			m_cAniInfo.SetNext("PlayerShieldAttack");
			m_cAniInfo.SetTime(0);
			m_cAniInfo.SetFrame(0);

		}
	}
}